#include "lua_api.h"

#include <unistd.h>

#include <cstdint>
#include <string>
#include <cstring>
#include <iostream>

#include "sunnet.h"
#include "packet_base.h"


LuaAPI::LuaAPI(/* args */)
{
}

LuaAPI::~LuaAPI()
{
}


void LuaAPI::Register(lua_State *lua_state){
    static luaL_Reg lualibs[] = {
        { "NewService", NewService },
        { "KillService", KillService },
        { "Send", Send },
        { "Listen", Listen },
        { "CloseConn", CloseConn },
        { "Write", Write },
        { "EntireWrite", EntireWrite },
        { NULL, NULL }
    };
    luaL_newlib(lua_state, lualibs);
    lua_setglobal(lua_state, "Lua2Cpp");
}

int LuaAPI::NewService(lua_State *lua_state){
    // 参数个数
    int num = lua_gettop(lua_state);  // 获取参数的个数
    // 参数1：服务类型
    if(lua_isstring(lua_state, 1) == 0){  // 1:是 0:不是
        lua_pushinteger(lua_state, -1);
        return 1;
    }

    size_t len = 0;
    const char *type = lua_tolstring(lua_state, 1, &len);
    char * newstr = new char[len + 1];  // 后面加\0
    newstr[len] = '\0';
    // 该字符串由lua虚拟机管理，为了安全，避免可能的冲突，需要重新拷贝一份由c++管理
    memcpy(newstr, type, len);
    auto t = std::make_shared<std::string>(newstr);
    // 处理
    uint32_t id = Sunnet::GetInstance().NewService(t);
    // 返回值
    lua_pushinteger(lua_state, id);
    return 1;
}

int LuaAPI::KillService(lua_State *lua_state){
    // 参数个数
    int num = lua_gettop(lua_state);  // 获取参数的个数
    LOG_DEBUG("KillService num:{}", num);
    // 参数1：服务类型
    if(lua_isinteger(lua_state, 1) == 0){  // 1:是 0:不是
        lua_pushinteger(lua_state, -1);
        return 0;
    }

    // 处理
    int service_id = lua_tointeger(lua_state, 1);
    LOG_DEBUG("KillService id:{}", service_id);
    Sunnet::GetInstance().KillService(service_id);

    // 返回值，无

    return 0;
}

int LuaAPI::Send(lua_State *lua_state){
    // 参数总数
    int num = lua_gettop(lua_state);
    if(num != 3) {
        LOG_ERR("Send fail, num err");
        return 0;
    }

    // 参数1:我是谁
    if(lua_isinteger(lua_state, 1) == 0) {
        LOG_ERR("Send fail, arg1 err");
        return 0;
    }
    int source = lua_tointeger(lua_state, 1);

    // 参数2:发送给谁
    if(lua_isinteger(lua_state, 2) == 0) {
        LOG_ERR("Send fail, arg2 err");
        return 0;
    }
    int dest = lua_tointeger(lua_state, 2);

    // 参数3:发送的内容
    if(lua_isstring(lua_state, 3) == 0){
        LOG_ERR("Send fail, arg3 err");
        return 0;
    }
    size_t len = 0;
    const char *buff = lua_tolstring(lua_state, 3, &len);
    char * newstr = new char[len];
    memcpy(newstr, buff, len);

    // 处理
    auto msg= std::make_shared<ServiceMsg>();
    msg->SetType(BaseMsg::MsgType::SERVICE);
    msg->SetSource(source);
    msg->SetBuff(newstr);
    msg->SetSize(len);
    Sunnet::GetInstance().Send(dest, msg);

    // 返回值：无

    return 0;
}

int LuaAPI::Listen(lua_State *lua_state){
    // 参数个数
    int num = lua_gettop(lua_state);
    // 参数1：端口
    if(lua_isinteger(lua_state, 1) == 0) {
        lua_pushinteger(lua_state, -1);
        return 1;
    }
    int port = lua_tointeger(lua_state, 1);

    // 参数2：服务Id
    if(lua_isinteger(lua_state, 2) == 0) {
        lua_pushinteger(lua_state, -1);
        return 1;
    }
    int id = lua_tointeger(lua_state, 2);

    // 处理
    int fd = Sunnet::GetInstance().Listen(port, id);
    // 返回值
    lua_pushinteger(lua_state, fd);
    return 1;
}

int LuaAPI::CloseConn(lua_State *lua_state){
    // 参数个数
    int num = lua_gettop(lua_state);
    // 参数1：fd
    if(lua_isinteger(lua_state, 1) == 0) {
        return 0;
    }
    int fd = lua_tointeger(lua_state, 1);
    // 处理
    Sunnet::GetInstance().CloseConn(fd);
    // 返回值
    //（无）
    return 0;
}

int LuaAPI::Write(lua_State *lua_state){
    //参数个数
    int num = lua_gettop(lua_state);
    //参数1：fd
    if(lua_isinteger(lua_state, 1) == 0) {
        lua_pushinteger(lua_state, -1);
        return 1;
    }
    int fd = lua_tointeger(lua_state, 1);
    //参数2：buff
    if(lua_isstring(lua_state, 2) == 0){
        lua_pushinteger(lua_state, -1);
        return 1;
    }
    size_t len = 0;
    const char *buff = lua_tolstring(lua_state, 2, &len);
    //处理
    int r = ::write(fd, buff, len);
    //返回值
    lua_pushinteger(lua_state, r);
    return 1;
}

int LuaAPI::EntireWrite(lua_State *lua_state){
    LOG_DEBUG("EntireWrite");
    // 参数个数
    int num = lua_gettop(lua_state);
    if(num != 3){
        LOG_ERR("EntireWrite fail, num err");
        return 0;
    }

    // 参数1：service_id
    if(lua_isinteger(lua_state, 1) == 0) {
        lua_pushinteger(lua_state, -1);
        return 1;
    }
    int service_id = lua_tointeger(lua_state, 1);

    // 参数2：fd
    if(lua_isinteger(lua_state, 2) == 0) {
        lua_pushinteger(lua_state, -1);
        return 1;
    }
    int fd = lua_tointeger(lua_state, 2);

    // 参数3：buff
    if(lua_isstring(lua_state, 3) == 0){
        lua_pushinteger(lua_state, -1);
        return 1;
    }
    size_t len = 0;
    const char *buff = lua_tolstring(lua_state, 3, &len);
    char * newstr = new char[len];
    memcpy(newstr, buff, len);

    auto conn = Sunnet::GetInstance().GetConn(fd);
    if(conn == nullptr){
        LOG_ERR("EntireWrite fail, conn err");
        lua_pushinteger(lua_state, -1);
        return 1;
    }

    conn->GetWriter()->EntireWrite(std::shared_ptr<char>(newstr), len);
    lua_pushinteger(lua_state, 1);

    return 1;
}
